第5章 オブジェクト指向原則 SOLID
クラス設計の原則(扉)
SOLID原則5つ紹介
オブジェクト指向言語に特化したものではない
1章 クリーンアーキテクチャで残されていた謎が明かされる(オブジェクト指向ではDIPが自然)
SRP:単一責任原則
2つの例
ニュース記事管理
入稿(draft)と購読(subscribe)を分ける
ArticleDraftOperationとArticleSubscribeOperationを別々に変更できる
データベースドライバ
readとwriteは分けない
バージョン1のドライバとバージョン2のドライバ
分けすぎると、readはバージョン1でwriteはバージョン2というちぐはぐが発生
クラスの責務は、何かの法則で機械的に決まるものではなく、将来の保守開発への想像から恣意的に生み出すもの (Kindle 版 p.152)
開発者の都合に無理やり意味づけをする (Kindle 版 p.152)
データベースドライバの例は、バージョンの区別を優先という意思決定をしたということ
(IMO:文脈が変われば別の設計もありうる)
開発を進める中で考え直しがある
OCP:開放閉鎖原則
仕様を削ぎ落として本質を分離する
安定度・抽象度等価の原則の発想
例:FizzBuzz
最初はベタ書きスクリプト
FizzルールとBuzzルールが順に適用されてFizzBuzzとなることを見破っている!
何もしないルールは、まだ何もされていない(carry引数が空文字列)ときだけapplyされる
何かしらがapplyされていたらcarry引数は何らかの文字列
一貫した法則をベースに、徹底してパーツを外せるように作られたもののほうがシンプル (Kindle 版 p.163)
長生きするとわかった部分からOCPを適用
LSP:リスコフの置換原則
正しい継承について
派生物は全く同じ使い方を保証しないといけない
すでに定着している仕様を勝手に変えない
(使っている箇所の)下位互換性
基底クラスにない事前条件(入力値の制限など)を加えてはいけない以外に、基底クラスが持っていた事後条件(出力結果など)の範囲を逸脱するのもNGです。(Kindle 版 p.169)
型レベルで分かる
TODO;手を動かしたい(mypy)
型の事後条件
同じかより狭い場合はOK。広げてはならない
型の事前条件
狭めてはならない。同じかより広い場合はOK
ISP:インターフェース分離原則
インターフェース版の単一責任原則
クラスはモジュールを提供するときの単位ですが、インターフェースは利用時の概念の最小単位です。(Kindle 版 pp.172-173)
IMO:小さなインターフェース、組み合わせる!
SRPのデータベースドライバの例の続き
(クラスはreadとwriteを持つ)
入力だけのインターフェースと出力だけのインターフェースを実装するドライバクラス(Mixin)
クラスはひとつ交換したら済むようにしつつ、そのクラスの利用者には「入力」「出力」という別の単位概念と認識させる (Kindle 版 p.173)
(IMO:inputがwriteでoutputがreadなの、すっと飲み込めない)
入力だけのインターフェースに依存する呼び出し側はwriteメソッドしか見えない(readを知らなくてもよい)
ラップトップPCの例
ポート(プラグ)、ビルトイン
図5-13に至る
理解したい
抽象ひとつに具象が複数
具象ひとつに抽象が複数
クライアントコードが異なるパッケージにある点がDBドライバの例と違う
実装より先に使用を想像し、複数の使うときの関心を結合させてしまうのを避ける (Kindle 版 p.189)
構造化プログラミングのデータ型にみんなが等しくアクセスするのは、オブジェクト指向とマッチしない
利用時の関心のみ(利用時の関心以外は不要)
だからインターフェース!
実体は隠蔽されて、利用側からは概念が部分的にしか見えません。(Kindle 版 p.189)
DIP:依存性逆転原則
トップダウン機能分解アプローチとは別物になる
オブジェクト指向プログラミングにおいては、安定抽象に向く依存の向きが、呼び出し構造の上位下位の関係に縛られない、独立したものであると言っている (Kindle 版 p.196)
トップダウン機能分解でうまくいく例:飽和関数
maxとminを使って実装
ISPのラップトップPCの例
サンプルコードで定義の順序が逆になる
USBKeyboardを作ってからそれを使うUSBPortを作る
安定抽象USBDeviceInterfaceを作り、それをUSBPortで使う。USBDeviceInterfaceを実装してUSBKeyboardを作る
OCPのFizzBuzzの例
呼び出し方向は本質側から仕様側へ(仕様を変えても本質を変えない)
インターフェースにDIPが適用されていた
クリーンアーキテクチャを実現する仕組み
最小のインターフェースに依存する
制御構造と依存関係が逆転する
オブジェクト指向ではこの逆転は自然
コラムより
SOLIDは「最短ルートでベテランに追いつくコツ」(巨人の肩に乗る)